import json
import logging
import sys

import serial.tools.list_ports
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QTimer

from digital_attenuator import DigitalAttenuator
from widgets.widgets import InstrumentInfoWidget
from calibration_thread import CalibrationThread
from measurement_calculator import CalibrationCalculator

class UiCalibrationWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.center_widget = QWidget()
        self.setCentralWidget(self.center_widget)
        # 状态栏
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage('就绪')

        """创建串口通信区域"""
        group_box = QGroupBox('串口通信')
        att_com_layout = QHBoxLayout(group_box)

        # COM端口选择
        port_layout = QVBoxLayout()
        port_label = QLabel('COM端口:')
        self.port_combo = QComboBox()
        refresh_btn = QPushButton('刷新')
        refresh_btn.clicked.connect(self.refresh_ports)
        port_layout.addWidget(port_label)
        port_layout.addWidget(self.port_combo)
        port_layout.addWidget(refresh_btn)

        # 连接控制
        control_layout = QVBoxLayout()
        self.connect_btn = QPushButton('连接串口')
        self.connect_btn.clicked.connect(self.connect_serial)
        self.disconnect_btn = QPushButton('断开串口')
        self.disconnect_btn.clicked.connect(self.disconnect_serial)
        self.disconnect_btn.setEnabled(False)
        control_layout.addWidget(self.connect_btn)
        control_layout.addWidget(self.disconnect_btn)

        att_com_layout.addLayout(port_layout)
        att_com_layout.addLayout(control_layout)

        # parent_layout.addWidget(group_box)

        # GroupBox: Instrument(校准涉及到的仪器仪表)
        self.group_box_of_instrument = QGroupBox("Instrument")
        self.group_box_of_instrument_layout = QVBoxLayout(self.group_box_of_instrument)
        self.sg_info_widget = InstrumentInfoWidget('SG', ['Keysight', "R&S"])
        self.sa_info_widget = InstrumentInfoWidget('SA', ['Keysight', "R&S"])
        self.group_box_of_instrument_layout.addWidget(self.sg_info_widget)
        self.group_box_of_instrument_layout.addWidget(self.sa_info_widget)

        # GroupBox: 校准的频率范围和特定的频点
        self.group_box_of_frequency_range = QGroupBox("Frequency Range")
        self.group_box_of_frequency_range_layout = QFormLayout(self.group_box_of_frequency_range)
        self.start_frequency_spin = QSpinBox()
        self.stop_frequency_spin = QSpinBox()
        self.step_frequency_spin = QDoubleSpinBox()
        self.step_frequency_spin.setMaximum(1000)
        self.rbw_editer_1 = QLineEdit()
        self.vbw_editer_1 = QLineEdit()
        self.span_editer_1 = QLineEdit()
        self.rbw_editer_2 = QLineEdit()
        self.vbw_editer_2 = QLineEdit()
        self.span_editer_2 = QLineEdit()
        self.group_box_of_frequency_range_layout.addRow("Start Frequency (MHz)", self.start_frequency_spin)
        self.group_box_of_frequency_range_layout.addRow("Stop Frequency (MHz)", self.stop_frequency_spin)
        self.group_box_of_frequency_range_layout.addRow("Step (MHz)", self.step_frequency_spin)
        self.group_box_of_frequency_range_layout.addRow("RBW(<1GHz)", self.rbw_editer_1)
        self.group_box_of_frequency_range_layout.addRow("VBW(<1GHz)", self.vbw_editer_1)
        self.group_box_of_frequency_range_layout.addRow("Span(<1GHz)", self.span_editer_1)
        self.group_box_of_frequency_range_layout.addRow("RBW(>1GHz)", self.rbw_editer_2)
        self.group_box_of_frequency_range_layout.addRow("VBW(>1GHz)", self.vbw_editer_2)
        self.group_box_of_frequency_range_layout.addRow("Span(>1GHz)", self.span_editer_2)
        # 默认数值
        self.stop_frequency_spin.setMaximum(40 * 1000)
        self.start_frequency_spin.setMaximum(40 * 1000)
        self.start_frequency_spin.setValue(30)
        self.stop_frequency_spin.setValue(6 * 1000)
        self.step_frequency_spin.setValue(100)
        self.rbw_editer_1.setText('1 kHz')
        self.vbw_editer_1.setText('30 kHz')
        self.rbw_editer_2.setText('1 kHz')
        self.vbw_editer_2.setText('30 kHz')
        self.span_editer_1.setText('100 kHz')
        self.span_editer_2.setText('100 kHz')

        # 指定/特殊频点
        self.specify_frequency_check_box = QCheckBox("Specify frequency(Blocking, Channels)")
        self.specify_frequency_check_box.setChecked(True)

        # 添加开始校准和停止校准按钮
        self.button_layout = QHBoxLayout()
        self.start_calibration_btn = QPushButton('开始校准')
        self.stop_calibration_btn = QPushButton('停止校准')
        self.button_layout.addWidget(self.start_calibration_btn)
        self.button_layout.addWidget(self.stop_calibration_btn)

        # 添加导入参考线线损文件功能模块
        self.import_loss_file_layout = QHBoxLayout()
        self.import_loss_file_btn = QPushButton('导入参考线线损文件')
        self.import_loss_file_layout.addWidget(self.import_loss_file_btn)

        # 添加衰减器步进设置区域
        self.attenuator_step_group_box = QGroupBox("衰减器步进设置")
        self.attenuator_step_layout = QHBoxLayout(self.attenuator_step_group_box)
        self.start_attenuation_label = QLabel('开始值:')
        self.start_attenuation_spin = QDoubleSpinBox()
        self.start_attenuation_spin.setValue(0)
        self.start_attenuation_spin.setRange(0, 90)
        self.stop_attenuation_label = QLabel('结束值:')
        self.stop_attenuation_spin = QDoubleSpinBox()
        self.stop_attenuation_spin.setValue(90)
        self.stop_attenuation_spin.setRange(0, 90)
        self.step_attenuation_label = QLabel('步进值:')
        self.step_attenuation_spin = QDoubleSpinBox()
        self.step_attenuation_spin.setValue(5)
        self.step_attenuation_spin.setRange(0, 20)
        self.attenuator_step_layout.addWidget(self.start_attenuation_label)
        self.attenuator_step_layout.addWidget(self.start_attenuation_spin)
        self.attenuator_step_layout.addWidget(self.stop_attenuation_label)
        self.attenuator_step_layout.addWidget(self.stop_attenuation_spin)
        self.attenuator_step_layout.addWidget(self.step_attenuation_label)
        self.attenuator_step_layout.addWidget(self.step_attenuation_spin)
        # 添加测量统计信息显示区域
        self.measurement_info_group_box = QGroupBox("测量统计信息")
        self.measurement_info_layout = QVBoxLayout(self.measurement_info_group_box)
        
        # 创建信息显示标签
        self.freq_points_label = QLabel('频率点数: 计算中...')
        self.att_points_label = QLabel('衰减点数: 计算中...')
        self.total_measurements_label = QLabel('总测量次数: 计算中...')
        self.estimated_time_label = QLabel('预估时长: 计算中...')
        
        # 设置标签样式
        info_style = "QLabel { padding: 2px; border: 1px solid #ccc; background-color: #f9f9f9; }"
        self.freq_points_label.setStyleSheet(info_style)
        self.att_points_label.setStyleSheet(info_style)
        self.total_measurements_label.setStyleSheet(info_style)
        self.estimated_time_label.setStyleSheet(info_style)
        
        self.measurement_info_layout.addWidget(self.freq_points_label)
        self.measurement_info_layout.addWidget(self.att_points_label)
        self.measurement_info_layout.addWidget(self.total_measurements_label)
        self.measurement_info_layout.addWidget(self.estimated_time_label)

        # Tab
        self.tab_view = QTabWidget()
        # log View
        self.log_view = QPlainTextEdit()
        self.tab_view.addTab(self.log_view, 'Log')

        # 进度条
        self.power_progress_bar = QProgressBar(self)
        self.power_progress_bar.setMaximum(100)
        self.power_progress_bar.setMinimum(0)

        self.right_layout = QVBoxLayout()
        self.right_layout.addWidget(self.tab_view)
        self.right_layout.addWidget(self.power_progress_bar)

        self.left_layout = QVBoxLayout()
        self.left_layout.addWidget(group_box)
        self.left_layout.addWidget(self.group_box_of_instrument)
        self.left_layout.addWidget(self.group_box_of_frequency_range)
        self.left_layout.addWidget(self.specify_frequency_check_box)
        self.left_layout.addLayout(self.import_loss_file_layout)
        self.left_layout.addWidget(self.attenuator_step_group_box)
        self.left_layout.addWidget(self.measurement_info_group_box)



        self.h = QHBoxLayout()
        self.h.addLayout(self.left_layout)
        self.h.addLayout(self.right_layout)
        self.h.setStretch(0, 3)
        self.h.setStretch(1, 7)

        # 布局
        self.v = QVBoxLayout()
        self.v.addLayout(self.h)
        self.v.addLayout(self.button_layout)

        self.center_widget.setLayout(self.v)
        pass

class CalibrationWindow(UiCalibrationWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.refresh_ports()
        self.attenuator = None
        
        # 初始化校准线程为空
        self.calibration_thread = None

        self.sa_info_widget.vias_address_editer.setText('TCPIP0::192.168.8.201::inst0::INSTR')
        self.sg_info_widget.vias_address_editer.setText('TCPIP0::192.168.1.102::inst0::INSTR')
        
        # 连接按钮信号
        self.start_calibration_btn.clicked.connect(self.start_calibration)
        self.stop_calibration_btn.clicked.connect(self.stop_calibration)
        self.import_loss_file_btn.clicked.connect(self.import_loss_file)
        
        # 初始化参考线线损数据
        self.reference_loss_data = {}
        
        # 初始化测量计算器
        self.calculator = CalibrationCalculator()
        
        # 创建定时器用于实时更新测量信息
        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.update_measurement_info)
        self.update_timer.start(1000)  # 每秒1秒更新一次
        
        # 连接参数改变信号
        self.start_frequency_spin.valueChanged.connect(self.on_parameter_changed)
        self.stop_frequency_spin.valueChanged.connect(self.on_parameter_changed)
        self.step_frequency_spin.valueChanged.connect(self.on_parameter_changed)
        self.start_attenuation_spin.valueChanged.connect(self.on_parameter_changed)
        self.stop_attenuation_spin.valueChanged.connect(self.on_parameter_changed)
        self.step_attenuation_spin.valueChanged.connect(self.on_parameter_changed)
        self.specify_frequency_check_box.stateChanged.connect(self.on_parameter_changed)
        
        # 初始化测量信息显示
        self.update_measurement_info()
        pass

    def refresh_ports(self):
        """刷新串口列表"""
        self.port_combo.clear()
        ports = [p.device for p in serial.tools.list_ports.comports()]
        self.port_combo.addItems(ports)
        if ports:
            self.status_bar.showMessage(f'找到 {len(ports)} 个可用端口')
        else:
            self.status_bar.showMessage('未找到可用端口')

    def connect_serial(self):
        """连接串口"""
        if self.attenuator is not None:
            self.attenuator.disconnect()

        port = self.port_combo.currentText()
        if not port:
            QMessageBox.warning(self, '警告', '请选择一个COM端口')
            return

        try:
            self.attenuator = DigitalAttenuator(port)
            self.attenuator.connect()

            # 更新UI状态
            self.connect_btn.setEnabled(False)
            self.disconnect_btn.setEnabled(True)
            self.status_bar.showMessage(f'已连接至 {port}')
            logging.info(f'成功连接到 {port}')

        except Exception as e:
            QMessageBox.critical(self, '错误', f'连接失败: {str(e)}')
            logging.error(f'连接 {port} 失败: {str(e)}')

    def disconnect_serial(self):
        """断开串口"""
        if self.attenuator is not None:
            try:
                self.attenuator.disconnect()
                logging.info('串口已断开')
            except Exception as e:
                logging.error(f'断开连接时出错: {str(e)}')
            finally:
                self.attenuator = None

        # 更新UI状态
        self.connect_btn.setEnabled(True)
        self.disconnect_btn.setEnabled(False)
        self.status_bar.showMessage('串口已断开')
        
    def start_calibration(self):
        """开始校准"""
        # 检查是否已连接衰减器
        if self.attenuator is None:
            QMessageBox.warning(self, '警告', '请先连接衰减器')
            return
            
        # 检查校准线程是否已经在运行
        if self.calibration_thread is not None and self.calibration_thread.isRunning():
            QMessageBox.information(self, '提示', '校准正在进行中...')
            return
            
        # 获取界面参数
        start_freq = self.start_frequency_spin.value()
        stop_freq = self.stop_frequency_spin.value()
        step_freq = self.step_frequency_spin.value()
        
        start_att = self.start_attenuation_spin.value()
        stop_att = self.stop_attenuation_spin.value()
        step_att = self.step_attenuation_spin.value()
        
        rbw_1 = self.rbw_editer_1.text()
        vbw_1 = self.vbw_editer_1.text()
        span_1 = self.span_editer_1.text()
        rbw_2 = self.rbw_editer_2.text()
        vbw_2 = self.vbw_editer_2.text()
        span_2 = self.span_editer_2.text()
        
        # 获取指定频率选项状态
        specify_frequency_enabled = self.specify_frequency_check_box.isChecked()
        
        # 创建并启动校准线程
        self.calibration_thread = CalibrationThread(
            self.attenuator, self.sg_info_widget, self.sa_info_widget,
            start_freq, stop_freq, step_freq,
            start_att, stop_att, step_att,
            rbw_1, vbw_1, span_1, rbw_2, vbw_2, span_2,
            self.reference_loss_data,  # 传递参考线线损数据
            specify_frequency_enabled  # 传递指定频率选项
        )
        
        # 连接信号
        self.calibration_thread.progress_signal.connect(self.update_progress)
        self.calibration_thread.log_signal.connect(self.add_log)
        self.calibration_thread.finished_signal.connect(self.calibration_finished)
        
        # 启动线程
        self.calibration_thread.start()
        
        # 更新UI状态
        self.start_calibration_btn.setEnabled(False)
        self.status_bar.showMessage('校准进行中...')
        
    def stop_calibration(self):
        """停止校准"""
        if self.calibration_thread is not None and self.calibration_thread.isRunning():
            self.calibration_thread.stop()
            self.status_bar.showMessage('正在停止校准...')
            
    def update_progress(self, progress):
        """更新进度条"""
        self.power_progress_bar.setValue(progress)
        
    def add_log(self, message):
        """添加日志信息"""
        self.log_view.appendPlainText(message)
        
    def calibration_finished(self, success):
        """校准完成回调"""
        if success:
            self.status_bar.showMessage('校准完成')
            self.log_view.appendPlainText('校准完成')
        else:
            self.status_bar.showMessage('校准失败')
            self.log_view.appendPlainText('校准失败')
        
    def import_loss_file(self):
        """导入参考线线损文件"""
        try:
            # 打开文件选择对话框
            file_dialog = QFileDialog()
            file_path, _ = file_dialog.getOpenFileName(
                self,
                '选择参考线线损文件',
                '',
                'JSON Files (*.json);;All Files (*)'
            )
            
            if file_path:
                # 读取JSON文件
                with open(file_path, 'r', encoding='utf-8') as f:
                    self.reference_loss_data = json.load(f)
                
                # 显示成功信息
                file_name = file_path.split('/')[-1].split('\\')[-1]
                self.status_bar.showMessage(f'已成功导入参考线线损文件: {file_name}')
                self.add_log(f'成功导入参考线线损文件: {file_name}')
                self.add_log(f'线损数据点数: {len(self.reference_loss_data)}')
                
                # 更新按钮显示状态
                self.import_loss_file_btn.setText(f'已导入: {file_name}')
                self.import_loss_file_btn.setStyleSheet('QPushButton { background-color: #4CAF50; color: white; }')
                
                QMessageBox.information(
                    self, 
                    '成功', 
                    f'成功导入参考线线损文件\n文件: {file_name}\n线损数据点数: {len(self.reference_loss_data)}'
                )
                
        except json.JSONDecodeError as e:
            error_msg = f'JSON文件格式错误: {str(e)}'
            QMessageBox.critical(self, '错误', error_msg)
            self.add_log(f'错误: {error_msg}')
            
        except Exception as e:
            error_msg = f'导入文件失败: {str(e)}'
            QMessageBox.critical(self, '错误', error_msg)
            self.add_log(f'错误: {error_msg}')
    
    def get_reference_loss(self, frequency):
        """获取指定频率的参考线线损"""
        if not self.reference_loss_data:
            return 0.0
            
        try:
            # 将频率转换为字符串格式
            freq_str = str(float(frequency))
            
            # 直接查找
            if freq_str in self.reference_loss_data:
                return float(self.reference_loss_data[freq_str])
            
            # 如果没有直接匹配，找最接近的频率点
            frequencies = [float(f) for f in self.reference_loss_data.keys()]
            closest_freq = min(frequencies, key=lambda x: abs(x - float(frequency)))
            
            return float(self.reference_loss_data[str(closest_freq)])
            
        except Exception as e:
            self.add_log(f'获取参考线线损失败: {str(e)}')
            return 0.0
    
    def on_parameter_changed(self):
        """参数改变时的处理"""
        # 将更新推迟到下一个事件循环，避免频繁计算
        if hasattr(self, 'update_timer'):
            self.update_timer.stop()
            self.update_timer.start(500)  # 500ms后更新
    
    def update_measurement_info(self):
        """更新测量统计信息显示"""
        try:
            # 获取当前参数
            start_freq = self.start_frequency_spin.value()
            stop_freq = self.stop_frequency_spin.value()
            step_freq = self.step_frequency_spin.value()
            
            start_att = self.start_attenuation_spin.value()
            stop_att = self.stop_attenuation_spin.value()
            step_att = self.step_attenuation_spin.value()
            
            # 获取指定频率选项状态
            specify_frequency_enabled = self.specify_frequency_check_box.isChecked()
            
            # 参数验证
            if step_freq <= 0 or step_att <= 0:
                self._show_calculation_error("步进值必须大于0")
                return
                
            if start_freq >= stop_freq:
                self._show_calculation_error("起始频率必须小于结束频率")
                return
                
            if start_att >= stop_att:
                self._show_calculation_error("起始衰减必须小于结束衰减")
                return
            
            # 计算测量统计
            result = self.calculator.calculate_measurement_count(
                start_freq, stop_freq, step_freq,
                start_att, stop_att, step_att,
                specify_frequency_enabled
            )
            
            # 更新显示
            if specify_frequency_enabled and 'special_freq_points' in result:
                # 显示特殊频率信息
                regular_count = result.get('regular_freq_points', 0)
                special_count = result.get('special_freq_points', 0)
                total_freq = result['frequency_points']
                self.freq_points_label.setText(
                    f"📍 频率点数: {total_freq:,} 个 (常规{regular_count}个 + 特殊{special_count}个)"
                )
            else:
                # 只显示常规频率
                self.freq_points_label.setText(f"📍 频率点数: {result['frequency_points']:,} 个")
            self.att_points_label.setText(f"🔧 衰减点数: {result['attenuation_points']:,} 个")
            self.total_measurements_label.setText(f"📊 总测量次数: {result['total_measurements']:,} 次")
            
            # 格式化时间显示
            time_str = self.calculator.format_time_estimation(result['time_estimation'])
            self.estimated_time_label.setText(f"⏱️ 预估时长: {time_str}")
            
            # 根据测量次数调整标签颜色
            total = result['total_measurements']
            if total > 10000:
                color = "#ff6b6b"  # 红色 - 大量测量
                warning = " ⚠️ 测量量较大"
            elif total > 5000:
                color = "#ffa726"  # 橙色 - 中等测量
                warning = " ⚠️ 测量量中等"
            elif total > 1000:
                color = "#66bb6a"  # 绿色 - 正常测量
                warning = " ✅ 测量量正常"
            else:
                color = "#42a5f5"  # 蓝色 - 少量测量
                warning = " ✨ 快速测试"
                
            style = f"QLabel {{ padding: 4px; border: 2px solid {color}; background-color: {color}20; font-weight: bold; }}"
            self.total_measurements_label.setStyleSheet(style)
            self.total_measurements_label.setText(f"📊 总测量次数: {total:,} 次{warning}")
            
            # 更新状态栏
            self.status_bar.showMessage(f'测量计划: {total:,}次测量, 预估{time_str}')
            
        except Exception as e:
            self._show_calculation_error(f"计算错误: {str(e)}")
    
    def _show_calculation_error(self, message):
        """显示计算错误信息"""
        error_style = "QLabel { padding: 4px; border: 2px solid #f44336; background-color: #f4433620; color: #f44336; font-weight: bold; }"
        
        self.freq_points_label.setText(f"⚠️ 频率点数: {message}")
        self.att_points_label.setText(f"⚠️ 衰减点数: {message}")
        self.total_measurements_label.setText(f"⚠️ 总测量次数: {message}")
        self.estimated_time_label.setText(f"⚠️ 预估时长: {message}")
        
        self.freq_points_label.setStyleSheet(error_style)
        self.att_points_label.setStyleSheet(error_style)
        self.total_measurements_label.setStyleSheet(error_style)
        self.estimated_time_label.setStyleSheet(error_style)

if __name__ == '__main__':
    app = QApplication([])
    window = CalibrationWindow()
    window.show()
    app.exec_()
    sys.exit(app.exec_())